﻿using System.Windows;
using System.Windows.Threading;
using System.Runtime.Serialization;
using System;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;

namespace Odyssey.ViewModels
{
    [DataContract]
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        /// <summary>
        /// Gets the current UI dispatcher.
        /// </summary>
        //public Dispatcher Dispatcher { get { return Application.Current.RootVisual.Dispatcher; } }
        public Dispatcher Dispatcher { get { return Deployment.Current.Dispatcher; } }

        public bool NotifyOnDispatcher { get; set; }

        /// <summary>
        /// Gets the NavigationService from the currently active page, otherwise null.
        /// </summary>
        public NavigationService NavigationService
        {
            get
            {
                var page = Page;
                return page != null ? page.NavigationService : null;
            }
        }

        public PhoneApplicationFrame Frame
        {
            get
            {
                return Application.Current.RootVisual as PhoneApplicationFrame;
            }
        }

        /// <summary>
        /// Gets the active page.
        /// </summary>
        public PhoneApplicationPage Page
        {
            get
            {
                var frame = Application.Current.RootVisual as PhoneApplicationFrame;
                return frame != null ? frame.Content as PhoneApplicationPage : null;
            }
        }

        protected void BeginInvoke(Action action)
        {
            Dispatcher.BeginInvoke(action);
        }

        protected void OnPropertyChanged(string propertyName)
        {
            CheckPropertyName(propertyName);
            var eh = PropertyChanged;


            if (eh != null)
            {
                if (NotifyOnDispatcher)
                {
                    Dispatcher.BeginInvoke(() => eh(this, new PropertyChangedEventArgs(propertyName)));
                }
                else
                {
                    eh(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }

        [Conditional("DEBUG")]
        private void CheckPropertyName(string name)
        {
            if (!this.GetType().GetProperties().Any(p => p.Name == name))
            {
                throw new ArgumentOutOfRangeException(name, "property not found on class " + this.GetType().Name + ".");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
